/*
 * @Author: OreoWang
 * @Email: ihc523@163.com
 * @Date: 2022-04-07 14:12:09
 * @LastEditors: OreoWang
 * @LastEditTime: 2022-04-26 10:51:23
 * @Description: 
 */

import { _decorator, Component, JsonAsset, director, Node, Scene } from "cc";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;

import * as bt from "../main";
import { BehaviorNode, IBehaviorTree, TLogOptions, BehaviorTreeUtils, Blackboard, logger, BehaviorStatus, TBlackboardOption } from "../main";

import BehaviorButton from "./BehaviorButton";
import BehaviorManager from "./BehaviorManager";

export type TTreeAsset = {
    root: any;
    refs: Array<string>;
    blackboard: TBlackboardOption
}

const logOptions: TLogOptions = {
    logEnter: false,
    logExit: false,

    logEnable: false,
    logDisable: false,

    logLoad: false,
    logDestroy: false,

    logUpdate: false,
    logExecute: true,
    logAbort: false,
}

@ccclass("BehaviorTree")
@requireComponent(BehaviorButton)
@disallowMultiple
export default class BehaviorTree extends Component implements IBehaviorTree {
    @property({
        type: JsonAsset,
        tooltip: "绑定行为树编辑器数据资源"
    })
    jsonAsset: JsonAsset = null;

    @property({
        tooltip: "节点激活时开始运行"
    })
    startWhenEnabled = true;

    @property({
        tooltip: "节点禁用时暂停运行"
    })
    pauseWhenDisabled = false;

    @property({
        tooltip: "当一次行为树全部结束时，重新开始执行该行为树"
    })
    restartWhenComplete = false;

    @property({
        tooltip: "当重新开始执行行为树时，重置各节点数据"
    })
    resetValuesOnRestart = false;

    @property({
        tooltip: "输出行为树执行日志"
    })
    logTaskChanges = false;

    isSuspended: boolean = false;
    isCompleted: boolean = false;
    status: BehaviorStatus = BehaviorStatus.None;
    blackboard: Blackboard = null;
    protected _utils: BehaviorTreeUtils = null;
    protected _root: BehaviorNode = null;
    protected get _manager() {
        return BehaviorManager.getInstance();
    }

    logOptions: TLogOptions;
    duration = 0;
    deltaTime = 0;
    protected timestamp = null;
    protected ticks = 0;

    getTargetRoot() {
        // return this.targetRoot || director.getScene() as unknown as Node;
        return this.node;
    }
    getTargetByUUID(uuid: string) {
        return this._utils?.getTarget(uuid);
    }
    getTargetByPath(path: string){
        return this._utils?.getTargetByPath(this.node, path);
    }
    onLoad() {
        if (!this.jsonAsset?.json) return;

        this.logOptions = logOptions;

        const json: TTreeAsset = this.jsonAsset.json as unknown as any;
        let uuids = json.refs || [];
        this._utils = new BehaviorTreeUtils();
        // this._utils.initAllTarget(this.getTargetRoot(), uuids);
        this.blackboard = new Blackboard(this, json.blackboard);
        if (this.loadTree(json)) {
            this._manager.runBehavior(this);
        }
    }
    onDestroy() {
        if (this._root) {
            this._manager.removeBehavior(this);
        }
    }

    loadTree(tree: TTreeAsset) {
        if (!tree?.root) {
            logger.error('load failed -- tree is invalid')
            return false;
        }

        // 创建根节点
        const options = tree.root.config?.label || {};
        if (options.uuid) {
            const instance = BehaviorNode.deserializeNode(null, tree.root, this);
            if (instance) {
                this._root = instance
                return true;
            }
            else {
                logger.error("Can't find class by uuid: ", options.uuid);
            }
        }
        return false;
    }

    onTick(delta: number) {
        if (!this._root) {
            logger.error('tick failed -- root is null')
            return
        }

        this.deltaTime = delta;
        this.duration += delta
        this.ticks += 1

        this.logTaskChanges && logger.log(`[ Execute BehaviorTree -- ${this._root.options.title} ]`)
        this.status = this._root.execute();

        return this.status;
    }

    onFinished() {
        this.isCompleted = true;
    }
    onRestart() {
        this.isCompleted = false;
        if (this.resetValuesOnRestart) {
            this._root.reset();
        }
    }

    onPause() {
        this.isSuspended = true;
    };
    onResume() {
        this.isSuspended = false;
    };
    onStop() {
        this.isSuspended = false;
        this.isCompleted = false;
    }
}